/*
 * Copyright 2009-2010 Nanjing RedOrange ltd (http://www.red-orange.cn)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package redora.util;

import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import org.jetbrains.annotations.NotNull;
import org.owasp.validator.html.AntiSamy;
import org.owasp.validator.html.CleanResults;
import org.owasp.validator.html.Policy;
import org.owasp.validator.html.PolicyException;
import org.owasp.validator.html.ScanException;

import redora.exceptions.FieldException;

import static java.util.logging.Level.INFO;

/**
 * AntiSamy HTML handler. Put in dirty HTML and clean HTML gets out.
 * @author Nanjing RedOrange (www.red-orange.cn)
 */
public class HtmlSanitizer {

    private static final transient Logger l = Logger.getLogger("redora.html.HtmlSanitizeFactory");
    private static final Map<String, Policy> cache = new HashMap<String, Policy>();
    //65k + something extra.
    public final static String MAX_INPUT_SIZE = "100000";

    private HtmlSanitizer() {
    } //prevent initialization

    @NotNull
    public static String clean(@NotNull String policy, @NotNull String dirtyHtml)
            throws FieldException {
        try {
            if (!cache.containsKey(policy)) {
                Policy pol = Policy.getInstance(ResourceFileHandler.findPolicy(policy));
                pol.setDirective(Policy.MAX_INPUT_SIZE,
                        MAX_INPUT_SIZE); //assuming a max size of 65k
                cache.put(policy, pol);
            }
        } catch (PolicyException e) {
            throw new FieldException("Failed to set policy (" + policy + ") file.", e);
        } catch (FileNotFoundException e) {
            throw new FieldException("Failed to set policy (" + policy + ") file.", e);
        }
        try {
            CleanResults cr = new AntiSamy().scan(dirtyHtml, cache.get(policy));
            for (Object error : cr.getErrorMessages()) {
                l.log(INFO, "Message in html handling for antisamy: {0}", error);
            }

            return cr.getCleanHTML();
        } catch (PolicyException e) {
            throw new FieldException("Failed due to policy error, have a look at your policy file " + policy, e);
        } catch (ScanException e) {
            throw new FieldException("Failed to scan html: " + dirtyHtml, e);
        }
    }
}
